#pragma once
#include "epoller.hpp"
#include "Connection.hpp"
#include <unordered_map>
#include <memory>
#include <iostream>

using namespace EpollerModule;
using connction_ptr = std::shared_ptr<Connection>;

class Reactor
{
private:
    std::shared_ptr<EpollerServer> _epolsvr;
    struct epoll_event _events[64];
    bool _isrunning;
    std::unordered_map<int, connction_ptr> _connections;

public:
    Reactor() : _epolsvr(std::make_shared<EpollerServer>()), _isrunning(false)
    {
    }
    void Loop()
    {
        _isrunning = true;
        while (_isrunning)
        {
            Looponce();
        }
        _isrunning = false;
    }
    void InsertConnection(connction_ptr con)
    {
        if (!IsHavConnection(con->GetFD()))
        {
            // 1. 添加进入_connectons
            _connections[con->GetFD()] = con;
            // 2. 填进入epoller模型
            _epolsvr->Add(con->GetFD(), con->GetEvent());
            // 3. 添加reactor指针
            con->SetOnwer(this);
            LOG(LogLevel::INFO) << "get a new connection: " << con->GetFD();
        }
        else
        {
            LOG(LogLevel::INFO) << "The connection: " << con->GetFD() << "already exsits";
        }
    }
    void DeletConnection(int fd)
    {
        // 如果有才删除
        if (IsHavConnection(fd))
        {
            // 1. 从epoll模型中删除
            _epolsvr->Delete(fd);            
            // 2. 关闭文件描述符
            _connections[fd]->Close();
            // 3. 从_connections中删除
            _connections.erase(fd);
            LOG(LogLevel::INFO) << "delete a connection: " << fd;
        }
        else
        {
            LOG(LogLevel::INFO) << "The connection: " << fd << "Not Found";
        }
    }
    ~Reactor() {}

private:
    void Looponce()
    {
        int n = _epolsvr->Wait(_events, 64);
        Dispacher(n);
    }
    bool IsHavConnection(int fd)
    {
        // 如果有返会true
        return _connections.find(fd) != _connections.end();
    }

    void Dispacher(int n)
    {
        // 到时候就这么执行
        for (int i = 0; i < n; i++)
        {
            int event = _events[i].events;
            int fd = _events[i].data.fd; // 为什么要设置fd？ 不就是现在要获取吗??
            // 一个epoll模型可能会有多个连接， 所以我们对每一个连接进行封装
            if ((event & EPOLLERR) || (event & EPOLLHUP)) // 如果异常了直接交给读写处理 TODO
                event = (EPOLLIN | EPOLLOUT);
            if ((event & EPOLLIN) && IsHavConnection(fd))
            {
                _connections[fd]->Reader();
            }
            if ((event & EPOLLOUT) && IsHavConnection(fd))
            {
                // TODO
                _connections[fd]->Sender(_connections[fd]->GetOuBuffer());
            }
        }
    }
};
